﻿using System.Collections.Generic;
using System.Linq;
using ControleRepresentante.Common;
using ControleRepresentanteSync.Application.Wizard;
using ControleRepresentanteSync.ControleRepresentanteServices;
using ControleRepresentanteSync.Logic;

namespace ControleRepresentanteSync.Application.DynamicSync
{
    abstract class DynamicSyncPresenter<TViewModel, TContentViewModel, TListViewModel, TContract> : WizardPagePresenterBase<TViewModel>
        where TContentViewModel : class, IDynamicSyncContentViewModel
        where TListViewModel : IDynamicSyncListViewModel<TContentViewModel>
        where TViewModel : IDynamicSyncViewModel<TContentViewModel, TListViewModel>
    {
        private readonly IWindow m_Window;
        private readonly IUserInterfaceService m_UserInterfaceService;
        private readonly ISyncServiceProvider m_SyncServiceProvider;

        protected DynamicSyncPresenter(IWindow window, TViewModel viewModel, IEnumerable<TContentViewModel> contents, IUserInterfaceService userInterfaceService, ISyncServiceProvider syncServiceProvider, IViewModelFactory viewModelFactory)
            : base(viewModel)
        {
            m_Window = window;
            m_UserInterfaceService = userInterfaceService;
            m_SyncServiceProvider = syncServiceProvider;

            ViewModel.Title = "Confirmação";
            ViewModel.Description = "Verifique na lista abaixo os dados informados para sincronização.";

            ViewModel.ContentList = viewModelFactory.CreateViewModel<TListViewModel>();
            ViewModel.ContentList.IsShowIsCheckedColumn = false;

            foreach (TContentViewModel contentViewModel in GetOrderedContents(contents))
            {
                ViewModel.ContentList.Contents.Add(contentViewModel);
            }

            ViewModel.IsValid = true;
        }

        protected abstract IEnumerable<TContentViewModel> GetOrderedContents(IEnumerable<TContentViewModel> contents);

        protected sealed override bool TryApply()
        {
            bool result = false;
            m_UserInterfaceService.ExecuteActionWithWaitMessage("Sincronizando", m_Window, () => m_UserInterfaceService.InvokeOnUIThread(() =>
            {
                try
                {
                    IEnumerable<TContract> contracts = ViewModel.ContentList.Contents
                        .Where(x => x.IsChecked)
                        .Select(ConvertToContract);

                    contracts.ExecuteBatch(20, x => m_SyncServiceProvider.Execute(syncService => Synchronize(syncService, x.ToArray())));

                    result = true;
                }
                catch
                {
                    result = false;
                }
            }));
            return result;
        }

        protected abstract void Synchronize(SyncService syncService, TContract[] contracts);
        protected abstract TContract ConvertToContract(TContentViewModel contentViewModel);
    }
}
